package com.example.demoofviewapp.pie;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;

import android.graphics.Typeface;
import android.text.TextPaint;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;

import com.example.demoofviewapp.R;
import com.example.demoofviewapp.pie.bean.PieItem;

import java.util.ArrayList;
import java.util.List;

public class PieButtonLayout extends FrameLayout {
    public static final int CIRCLE_ANGLE = 135;

    private static final int MAX_LEVEL = 5;
    private static final int DEFAULT_INNER_RADIUS = 0;
    private static final int DEFAULT_RADIUS_INC = 301;
    private static final int DEFAULT_START_ANGLE = 160;

    private Point mCenter;
    private int mInnerRadius;
    private int mRadiusInc;

    private OnItemClickListener mItemClickListener = null;

    private List<PieItem> mItemList;

    private Paint mNormalPaint;
    private Paint mPressedPaint;

    int mItemSize;
    private Context mContext;

    private PieItem mLastTouchItem = null;
    private boolean mIsLayoutItems = false;

    private boolean mIsTouchMove = false;
    private List<List<Path>> mOutRingList = new ArrayList<List<Path>>();

    public PieButtonLayout(@NonNull Context context) {
        super(context);
        init(context);
        mContext = context;
        mItemSize = (int) context.getResources().getDimension(R.dimen.pie_button_item_size);
    }

//    public PieButtonLayout(Context context, AttributeSet attrs, int defStyle) {
//        super(context, attrs, defStyle);
//        init(context);
//    }

    public void setOnItemClickListener(OnItemClickListener listener){
        mItemClickListener = listener;
    }

    private void init(Context ctx) {
        mItemList = new ArrayList();
        Resources res = ctx.getResources();

        mInnerRadius = DEFAULT_INNER_RADIUS;
        mRadiusInc = DEFAULT_RADIUS_INC;
        setWillNotDraw(false);
        setDrawingCacheEnabled(false);
        mCenter = new Point(0, 0);
        mNormalPaint = new Paint();
        mNormalPaint.setColor(res.getColor(R.color.teal_200));
        mNormalPaint.setAntiAlias(true);
        mPressedPaint = new Paint();
        mPressedPaint.setColor(res.getColor(R.color.pie_button_pressed));
        mPressedPaint.setAntiAlias(true);
    }

    public void addItem(PieItem item) {

        mItemList.add(item);
    }

    public void setCenter(Point center) {
        mCenter = center;
    }

    public void setCenter(int x, int y) {
        if (mCenter == null) {
            mCenter = new Point(x, y);
        } else {
            mCenter.x = x;
            mCenter.y = y;
        }
    }

    /**
     * @rget get Aradian)
     * @param angle
     * @return
     */
    private double angle2arc(int angle) {
        return (angle * Math.PI / 180);
    }

    private int arc2angle(double arc) {
        Log.d("arc to angle", "arc = " + arc);
        return (int) (arc * 180 / Math.PI);
    }

    private Path makePath(int startAngle, int endAngle, int inner, int outer, Point center) {
        Log.d("makePath", "start, end = " + startAngle + ", " + endAngle);
        Path path = new Path();
        RectF innerRect = new RectF(center.x - inner, center.y - inner,
                center.x + inner, center.y + inner);
        RectF outerRect = new RectF(center.x - outer, center.y - outer,
                center.x + outer, center.y + outer);
        path.arcTo(innerRect, startAngle, endAngle - startAngle, true);
        path.arcTo(outerRect, endAngle, startAngle - endAngle, false);
        path.close();
        return path;
    }

    private Path makePathForMiddle(int startAngle, int endAngle, int inner, int outer, int middleOffset,Point center) {
        Log.d("makePathForMiddle", "start, end = " + startAngle + ", " + endAngle);
        Path path = new Path();
        RectF innerRect = new RectF(center.x - inner, center.y - inner,
                center.x + inner, center.y + inner);
        RectF outerRect = new RectF(center.x - (outer-middleOffset), center.y - outer,
                center.x + (outer-middleOffset), center.y + outer);
        path.arcTo(innerRect, startAngle, endAngle - startAngle, true);
        path.arcTo(outerRect, endAngle, startAngle - endAngle, false);
        path.close();
        return path;
    }

    /**
     * @target Draw Cycle
     */
    private void layoutItems() {
        int intervalAngle = 1;
        int inner = mInnerRadius;
        int outer = mInnerRadius + mRadiusInc;
        int incInterval = 2;
        int startAngleInterval = 45;
        int levelStartAngle = DEFAULT_START_ANGLE;

        int itemAngle = CIRCLE_ANGLE / mItemList.size() - intervalAngle;
        int startAngle = levelStartAngle;
        mOutRingList.add(new ArrayList<>());
        mOutRingList.add(new ArrayList<>());
        Log.d("layout", "list.size = " + mItemList.size());
        for (PieItem item : mItemList) {
            View view = item.getView();
            view.measure(view.getLayoutParams().width,
                    view.getLayoutParams().height);
            int w = view.getMeasuredWidth();
            int h = view.getMeasuredHeight();
            //show in center
//            int r = inner + (outer - inner) / 2;
            // set TextView in Axial Center
            int r = (int) (inner + (outer - inner) / 1.3);
            double arc = angle2arc(startAngle + itemAngle / 2 + intervalAngle / 2);
            int x = mCenter.x + (int) (r * Math.cos(arc)) - w / 2;
            int y = mCenter.y + (int) (r * Math.sin(arc)) - h / 2;
            view.layout(x, y, x + w, y + h);
            // draw Shape
            Path path = makePath(startAngle, startAngle + itemAngle, inner, outer, mCenter);
            Path pathToOutRing = makePath(startAngle, startAngle + itemAngle, outer+5,outer+30,mCenter);
            mOutRingList.get(0).add(pathToOutRing);
            Path pathToRingStyle = makePathForMiddle(startAngle,startAngle+itemAngle,outer+5,outer+30,15,mCenter);
            mOutRingList.get(1).add(pathToRingStyle);
            item.setGeometry(startAngle, itemAngle, inner, outer, path);
            startAngle += itemAngle + intervalAngle;
        }

    }
    private PieItem findItem(float x, float y) {
        // find the matching item:
        Log.d("findItem", "x, y = " + x + " ," + y);
        x -= mCenter.x;
        y -= mCenter.y;
        int r = (int) Math.sqrt(x * x + y * y);
        int angle = arc2angle(Math.atan2(y, x));
        angle %= 360;
        if (angle < 0) {
            angle += 360;
        }
        Log.d("findItem", "r, angle = " + r + " ," + angle);

        for (PieItem item : mItemList) {
            if (isPointInItem(r, angle, item)) {
                return item;
            }
        }

        return null;
    }
    /**
     * is point with radius r and angle angle in item
     *
     * @param r     radius
     * @param angle angle witch is belong [0, 360)
     * @param item
     * @return yes point in the item, otherwise false
     */
    private boolean isPointInItem(int r, int angle, PieItem item) {
        if (item.getInnerRadius() <= r && item.getOuterRadius() >= r) {
            while (angle + CIRCLE_ANGLE <= item.getStartAngle() + item.getSweep()) {
                angle += CIRCLE_ANGLE;
            }
            if (item.getStartAngle() <= angle && item.getStartAngle() + item.getSweep() >= angle) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

    private int mLastTouchX;
    private int mLastTouchY;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        int action = event.getActionMasked();
        if (MotionEvent.ACTION_DOWN == action) {
            mLastTouchX = x;
            mLastTouchY = y;
            mIsTouchMove = false;
            mLastTouchItem = findItem(x, y);
            if (mLastTouchItem != null) {
                Log.d("touch", "item != null startAngle = " + mLastTouchItem.getStartAngle());
                mLastTouchItem.setPressed(true);
                invalidate();
            } else {
                Log.d("touch", "item == null");
            }
            return true;
        } else if (MotionEvent.ACTION_UP == action) {
            Log.d("touch", "up");
            if (mLastTouchItem != null) {
                mLastTouchItem.setPressed(false);
                invalidate();
            }
            if (!mIsTouchMove) {
                if (mItemClickListener != null && mLastTouchItem != null) {
                    mItemClickListener.onItemClick(mLastTouchItem);
                }
            }
        } else if (MotionEvent.ACTION_CANCEL == action) {
//        	mIsTouchMove = true;
        } else if (MotionEvent.ACTION_MOVE == action) {
            if (x != mLastTouchX || y != mLastTouchY) {
                mIsTouchMove = true;
            }
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if(!mIsLayoutItems){
            layoutItems();
            mIsLayoutItems = true;
        }
        int state;

        for (PieItem item : mItemList) {
            Paint p = item.isPressed() ? mPressedPaint : mNormalPaint;
            state = canvas.save();
            drawPath(canvas, item.getPath(), p);
            drawPath(canvas, mOutRingList.get(0).get(mItemList.indexOf(item)),p);
            Paint p1 = new Paint();
            p1.setColor(mContext.getResources().getColor(R.color.purple_200));
            drawPath(canvas, mOutRingList.get(1).get(mItemList.indexOf(item)),p1);
            canvas.restoreToCount(state);
            drawItem(canvas, item);
        }
    }
    @SuppressLint("NewApi")
    private void drawItem(Canvas canvas, PieItem item) {
        View view = item.getView();
        int state = canvas.save();
        canvas.translate(view.getX(), view.getY());
        view.draw(canvas);
        canvas.restoreToCount(state);
        state = canvas.save();
        canvas.restoreToCount(state);
    }

    private void drawPath(Canvas canvas, Path path, Paint paint) {
        canvas.drawPath(path, paint);
    }


//    @SuppressLint("ResourceAsColor")
    public PieItem makeItem(String str) {
//        RelativeLayout view = new RelativeLayout(mContext);
//        TextView textView = new TextView(view.getContext());
        TextView textView = new TextView(mContext);
        textView.setText(str);
        Resources res = mContext.getResources();
        textView.setTextColor(res.getColor(R.color.white));
        textView.setTextSize(36);
//        TextPaint paint = textView.getPaint();
//        paint.setFakeBoldText(true);
        // Active BOLD Text
        textView.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));

//        textView.setWidth(mItemSize);
//        textView.setHeight(mItemSize);
        textView.setMinimumHeight(mItemSize);
        textView.setMinimumWidth(mItemSize);
//        textView.setGravity(50);
//        view.addView(textView);
        LayoutParams lp = new LayoutParams(mItemSize, mItemSize);
        textView.setLayoutParams(lp);
        return new PieItem(textView);
    }

    public static interface OnItemClickListener{
        public void onItemClick(PieItem item);
    }
}
